package com.oldroid.apps.getit.service;

import java.io.File;
import java.net.URLConnection;

//import android.app.DownloadManager;
//import android.app.DownloadManager.Query;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

import com.oldroid.apps.getit.R;
import com.oldroid.apps.getit.provider.DownloadsContract.Downloads;
import com.oldroid.apps.getit.provider.DownloadsContract.Downloads_Tags;
import com.oldroid.apps.getit.provider.DownloadsContract.Tags;
import com.oldroid.apps.getit.util.DropBox;
import com.oldroid.apps.getit.util.UploadAsync;

public class DownloadWatcher extends Service {

	private static final String TAG = "DownloadWatcher";//
	private static final boolean LOGV = true;
	private DownloadObserver mObs;
	private SharedPreferences mPreferences;

	// Global mutable variables
	private Uri mUri;
	private String mimeType;

	private ContentResolver mContentResolver;
	//private DownloadManager dm; 

	public void onCreate() {
		mObs = new DownloadObserver("/sdcard/Download", FileObserver.CREATE, this);
		//mObs = new DownloadObserver("/sdcard/Downloa	d", FileObserver.CLOSE_WRITE, this);
		mObs.startWatching();
		mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		
		//dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
		
		
		
		
		
		//Toast.makeText(this, "Watch Service STARTED", Toast.LENGTH_LONG).show();
		log("Watch service started");
		
		//registerBroadcast();
		
		
		
	}
	
	
	private void say(String msg){
		Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
	}
	
	
	/*
	 * 
	private void registerBroadcast(){
		BroadcastReceiver br = new BroadcastReceiver() {
			
			@Override
			public void onReceive(Context context, Intent intent) {
				// TODO Auto-generated method stub
				
				log("OnReceive: " + intent.getAction());//
				say("OnReceive: " + intent.getAction()); 
				
				if(intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)){
					log("A Download has been completed"); 
					say("A Download has been completed");
					
					long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,0);
					Query query = new Query();
					query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
					Cursor c = dm.query(query);
					
					int count = c.getCount();
					
					say("We have "+count + "completed downloads");
					log("We have "+count + "completed downloads");
                            
					
				}
				
			}
		};
		
		//registerReceiver(br, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
		registerReceiver(br, new IntentFilter("android.intent.action.DOWNLOAD_COMPLETED")); // froyo
	}*/
	

	private void log(String msg){
		Log.d("DownloadWatcher", msg);
	}
	
	private class DownloadObserver extends FileObserver {
		private DownloadWatcher mDW;
		private String path;
		private String rootPath;

		public DownloadObserver(String path, int mask, DownloadWatcher dw) {
			super(path, mask);
			rootPath = path;
			mDW = dw;
		}

		public void onEvent(int event, String path) {
			mimeType = URLConnection.guessContentTypeFromName(path);
			this.path = rootPath + "/" + path;
			Log.v(TAG, "onEvent FIRED!!. path= " + path + "  File Full path: " + this.path);
			new FileFullyDownloadAsyncTask().execute(this.path, path);
			
			

		}

		private class FileFullyDownloadAsyncTask extends AsyncTask<String, Integer, String> {

			@Override
			protected String doInBackground(String... params) {
				try {
					File temp = new File(params[0]);
					
					while (true) {
						Log.v(TAG, "FileExistCheckAsyncTask. file size: " + temp.length() + " file exists: " + temp.exists());
						long before = temp.length();
						/**
						 * Use a five second interval so that we avoid the problem
						 * of having multiple downloads due to network connectivity problems. 
						 */
						Thread.sleep(5000); 
						temp = new File(params[0]);
						if(before == temp.length()){
							Log.v(TAG, "File size not changed recently -> Assuming Download DONE!!!!");
							break;
						}
					}
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				return params[1];
			}
			
			

			@Override
			protected void onProgressUpdate(Integer... values) {
				// TODO Auto-generated method stub
				
				super.onProgressUpdate(values);
			}



			@Override
			protected void onPostExecute(String result) {
				// TODO Auto-generated method stub
				super.onPostExecute(result);
				mDW.fileDownloaded(result);
				
				
			}

		}

	}

	public void fileDownloaded(String path) {
		File internalLoc = Environment.getDataDirectory();
		File externalLoc = Environment.getExternalStorageDirectory();
		String log = null;
		Log.w("DownloadWatcher", "getFilesDir: " + getFilesDir().getAbsolutePath());
		Log.w("DownloadWatcher", "getFilesDir.exists: " + getFilesDir().exists());
		boolean mounted = Environment.getExternalStorageState().equals("mounted");

		String loc_perf = mPreferences.getString("location_pref", "NOVALUE");
		Log.e("DownloadWatcher", "location_pref: " + loc_perf);
		String cat_perf = mPreferences.getString("category_pref", "NOVALUE");
		Log.e("DownloadWatcher", "category_pref: " + cat_perf);
		boolean local_perf = mPreferences.getBoolean("localcopy_pref", true); // true -> leave local copy by default if no explicit option is set
		Log.e("DownloadWatcher", "location_pref: " + local_perf);

		Log.e("DownloadWatcher", "Externation Storage Dir is : " + externalLoc.getAbsolutePath());

		/*
		 * Upload Location
		 */
		String newPath = "";

		newPath += externalLoc.getAbsolutePath() + "/" + getString(R.string.app_name) + "/";

		/*
		 * Category
		 */
		File temp = new File(newPath);

		int place = path.lastIndexOf(".");
		String tempDir = path.substring(0, place);
		int place2 = tempDir.lastIndexOf("/");
		String myFile = tempDir.substring(place2 + 1);

		if (!(temp.exists() && temp.isDirectory()))
			temp.mkdir();
		// File Extensions
		if (cat_perf.equals("media")) {
			if (mimeType == null) {
				int extensionStart = path.lastIndexOf(".");
				if (extensionStart != -1) {
					log = path.substring(extensionStart + 1);
					newPath += log + "/";
				} else {
					log = "misc";
					newPath += "misc/";
				}

			} else {
				if (LOGV)
					Log.v(TAG, "mimeType = " + mimeType);
				int index = mimeType.indexOf("/");
				log = mimeType.substring(0, index);
				newPath += log +"/";

			}
		}
		// File Name
		else if (cat_perf.equals("filename")) {

			String filename = mPreferences.getString("Filename Choice", "NOVALUE");
			if (LOGV)
				Log.v(TAG, "nameRule = " + filename);
			if (filename.equals("firstletter")) {
				int placeholder = path.lastIndexOf(".");
				String tempDirec = path.substring(0, placeholder);
				int placeholder2 = tempDirec.lastIndexOf("/");
				String firstLetter = tempDirec.substring(placeholder2 + 1, placeholder2 + 2);
				log = firstLetter;
				newPath += ("First letter of file name: " + firstLetter + "/");
			} else if (filename.equals("namelength")) {

				newPath += ("File name length: " + myFile.length() + "/");
				log = "" + myFile.length();
			}

		} else {
			int extensionStart = path.lastIndexOf(".");
			if (extensionStart != -1) {
				log = path.substring(extensionStart + 1);
				newPath += log + "/";
			} else {
				log = "misc";
				newPath += "misc/";
			}
		}


		File newDir = new File(newPath);
		if (!(newDir.exists() && newDir.isDirectory()))
			newDir.mkdir();
		File f = new File("/mnt/sdcard/Download/" + path);
		File f2 = new File(newPath + path);

		
		SharedPreferences.Editor edit = mPreferences.edit();

		edit.putString("LATEST_PATH", newPath); // was newPath before.
		edit.commit();

		
		// Move the File
		if (f.renameTo(f2))
			Log.w("DownloadWatcher", "Move successful");
		else
			Log.w("DownloadWatcher", "Move not successful");
	
	
		if (loc_perf.equals("dropbox")) {

			/*
			 * Update the LATEST_PATH to the correct value in Shared Prefs When
			 * dropbox is connected the newPath string is missing the
			 * /mnt/sdcard prefix.
			 */
			String latest_path = newPath;
			edit.putString("LATEST_PATH", latest_path); // save the correct path
														
			
			/* Get Dropbox Upload Dir Path
			 * 
			 * "/mnt/sdcard/Nimbus/jpeg/" is example of contents of newPath.
			 * 
			 * And we want to remove the constant "/mnt/sdcard/" so that we just have
			 * the relative file path. We do this using the substring method specifiying
			 * the first character in the new string to be at character index 11. 
			 * 
			 *  NB: This approach may not work on other devices if for instance the absolute
			 *  file path of the external location is different and not the expected "/mnt/sdcard"
			 * 
			 */
			String upload_path = newPath.substring(11); // see comment above
			
												
														
			edit.commit(); // save the changes

			Log.e("DownloadWatcher", "L-Path is "+latest_path);
			Log.e("DownloadWatcher", "Leave Local Copy ? "+local_perf);
			
			SharedPreferences data = this.getSharedPreferences(DropBox.CRED, MODE_PRIVATE);

			String key = data.getString("ACCESS_KEY", null);
			String secret = data.getString("ACCESS_SECRET", null);

			if (key == null || secret == null) { // then user has not connected
													// a dropbox account. SO do
													// nothing
				Log.d("DROPBOX", "User has not connected dropox account so we can't upload file to dropbox yet");
				return;
			}

			// otherwise use retrieved token to connect to dropbox.
			String[] keys = { key, secret };

			//Log.d("DROPBOX", "Download Watcher Retrieved tokens : key=" + key + " ; secret=" + secret);

			DropBox d = null;
			try {
				d = new DropBox(keys);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			if (!d.isConnected()) {
				Log.d("DROPBOX", "Connecting to dropbox failed using tokens failed Upload Halted. key=" + key
						+ " ; secret=" + secret);
				return; // stop here
			}

			UploadAsync uplo = new UploadAsync(this, f2.getAbsolutePath(), upload_path, !local_perf);
			uplo.execute(d);
			
		} 
		
		
		
		// Add downloaded file to the downloads database
		
		mContentResolver = getContentResolver();
		long timeStamp = System.currentTimeMillis();

		// Log.v("mUri", mUri.toString());
		ContentValues values = new ContentValues();
		// TODO: change the values
		values.put(Downloads.FILENAME, f2.getName());
		values.put(Downloads.URI, f2.getAbsolutePath());
		values.put(Downloads.CREATED, timeStamp);
		values.put(Downloads.MODIFIED, timeStamp);
		values.put(Downloads.TOTAL_BYTES, f2.length());
		values.put(Downloads.DELETED, !f2.exists());
		// put values into the downloads table
		mUri = mContentResolver.insert(Downloads.CONTENT_URI, values);
		
		
		
		values.clear();
		String download_id = mUri.getLastPathSegment();
		if(LOGV) Log.v(TAG, "uri= " + mUri.toString() + " _id= " + download_id);
		// put the tag into the tags table.
		log = log.toLowerCase();
		values.put(Tags.TAG, log);
		mUri = mContentResolver.insert(Tags.CONTENT_URI, values);
		values.clear();

		Cursor c = mContentResolver.query(Tags.CONTENT_URI, null, Tags.TAG + "=?", new String[]{log}, null);
		c.moveToNext();
		int tag_id = c.getInt(0);
		// put Downloads._id, Tags._id into the Donwloads_Tags table so we can query this info later
		values.put(Downloads_Tags.DOWNLOADS_ID, Integer.parseInt(download_id));
		values.put(Downloads_Tags.TAG_ID, tag_id);
		mUri = mContentResolver.insert(Downloads_Tags.CONTENT_URI, values);
		
		


		
	}

	public class LocalBinder extends Binder {
		DownloadWatcher getService() {
			return DownloadWatcher.this;
		}
	}

	private final IBinder mBinder = new LocalBinder();

	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	private class MoveOrCopyFileTask extends AsyncTask<File, Integer, Boolean> {

		@Override
		protected Boolean doInBackground(File... params) {
			// TODO Auto-generated method stub
			return null;
		}

	}

}
